from typing import Optional
import time as lib_time

from django.utils.translation import gettext as _
from django.db.models import QuerySet, Q

from core import errors
from apps.app_users.models import UserProfile, Email
from apps.app_tx_meeting.models import MeetingReservation, MeetingReservationLog


class MeetingReservationManager:
    @staticmethod
    def get_meeting_reservation_by_id(_id: str, select_for_update: bool = False) -> Optional[MeetingReservation]:
        if select_for_update:
            return MeetingReservation.objects.select_for_update().select_related('user').filter(id=_id).first()

        return MeetingReservation.objects.select_related('user').filter(id=_id).first()

    @staticmethod
    def get_user_meeting_reservation(_id: str, user: UserProfile) -> MeetingReservation:
        obj = MeetingReservation.objects.select_related('user').filter(id=_id).first()
        if obj is None:
            raise errors.TargetNotExist(message=_('会议预定记录不存在'))

        if obj.user_id != user.id and obj.tx_meeting_userid != user.username:
            raise errors.AccessDenied(message=_('您没有会议预定记录访问权限'))

        return obj

    @staticmethod
    def get_overlapping_reservations(start: int, end: int, room_type: int = None, tx_meeting_code: str = None) -> QuerySet:
        """
        与指定时间段有重叠的会议预定记录

        :raises: InvalidArgument
        """
        qs = MeetingReservation.objects.filter(
            room_reserve_start__lt=end,
            room_reserve_end__gt=start,
            status=MeetingReservation.Status.RESERVED.value
        )
        if room_type:
            qs = qs.filter(room_type=room_type)

        if tx_meeting_code:
            qs = qs.filter(tx_meeting_code=tx_meeting_code)

        qs = qs.order_by('start_time')
        return qs

    @staticmethod
    def create_meeting_reservation(
            subject: str,
            start_time: int, end_time: int,
            room_reserve_start: int, room_reserve_end: int,
            room_type: int, people_num: int,
            status: str,
            user: UserProfile,
            tx_meeting_id: str, tx_meeting_code: str,
            tx_start_time: int, tx_end_time: int,
            tx_meeting_userid: str, tx_user_nick_name: str,
            tx_join_url: str,
            room_reserve_status: str, room_reserve_desc: str,
            advance_notice_seconds: int, need_notice_time: int,
            email_notice: Optional[Email] = None
    ):
        obj = MeetingReservation(
            subject=subject,
            start_time=start_time,
            end_time=end_time,
            room_reserve_start=room_reserve_start,
            room_reserve_end=room_reserve_end,
            room_type=room_type,
            people_num=people_num,
            status=status,
            user=user,
            tx_meeting_id=tx_meeting_id,
            tx_meeting_code=tx_meeting_code,
            tx_start_time=tx_start_time,
            tx_end_time=tx_end_time,
            tx_meeting_userid=tx_meeting_userid,
            tx_user_nick_name=tx_user_nick_name,
            tx_join_url=tx_join_url,
            room_reserve_status=room_reserve_status,
            room_reserve_desc=room_reserve_desc,
            advance_notice_seconds=advance_notice_seconds,
            need_notice_time=need_notice_time,
            email_notice=email_notice
        )
        obj.save(force_insert=True)
        return obj

    @staticmethod
    def get_meeting_reservation_qs(
            user_id: Optional[str] = None,
            start_time_gte: Optional[int] = None,
            start_time_lte: Optional[int] = None,
            start_time_lt: Optional[int] = None,
            tx_meeting_code: Optional[str] = None,
            room_type: Optional[int] = None,
            status: Optional[str] = None,
            meeting_userid: Optional[str] = None
    ) -> QuerySet:
        """
        会议预定记录

        :param user_id: 预定提交人
        :param start_time_gte: 预定开始时间查询，>=
        :param start_time_lte: 预定开始时间查询，<=
        :param start_time_lt: 预定开始时间查询，<
        :param tx_meeting_code: 会议号查询
        :param room_type: 会议室类型
        :param status: 会议预定记录状态
        :param meeting_userid: 会议创建人查询
        """
        lookups = {}
        if user_id:
            lookups['user_id'] = user_id

        if start_time_gte:
            lookups['start_time__gte'] = start_time_gte

        if start_time_lte:
            lookups['start_time__lte'] = start_time_lte

        if start_time_lt:
            lookups['start_time__lt'] = start_time_lt

        if tx_meeting_code:
            lookups['tx_meeting_code'] = tx_meeting_code

        if room_type:
            lookups['room_type'] = room_type

        if status:
            lookups['status'] = status

        if meeting_userid:
            lookups['tx_meeting_userid'] = meeting_userid

        return MeetingReservation.objects.select_related('user').filter(**lookups).order_by('-creation_time')

    @staticmethod
    def get_user_meeting_reservation_qs(
            user: UserProfile,
            start_time_gte: Optional[int] = None,
            start_time_lte: Optional[int] = None,
            start_time_lt: Optional[int] = None,
            tx_meeting_code: Optional[str] = None,
            room_type: Optional[int] = None,
            status: Optional[str] = None,
    ) -> QuerySet:
        """
        会议预定记录

        :param user: 预定提交人
        :param start_time_gte: 预定开始时间查询，>=
        :param start_time_lte: 预定开始时间查询，<=
        :param start_time_lt: 预定开始时间查询，<
        :param tx_meeting_code: 会议号查询
        :param room_type: 会议室类型
        :param status: 会议预定记录状态
        """
        lookups = {}

        if start_time_gte:
            lookups['start_time__gte'] = start_time_gte

        if start_time_lte:
            lookups['start_time__lte'] = start_time_lte

        if start_time_lt:
            lookups['start_time__lt'] = start_time_lt

        if tx_meeting_code:
            lookups['tx_meeting_code'] = tx_meeting_code

        if room_type:
            lookups['room_type'] = room_type

        if status:
            lookups['status'] = status

        return MeetingReservation.objects.select_related('user').filter(
            Q(user_id=user.id) | Q(tx_meeting_userid=user.username)
        ).filter(**lookups).order_by('-creation_time')

    @staticmethod
    def set_reservation_notice_time(reservation: MeetingReservation, advance_minutes: int):
        """
        会前提醒通知时间设置

        :raises: InvalidArgument
        """
        if advance_minutes < 15:
            raise errors.InvalidArgument(message=_('会前提醒通知至少提前15分钟'))

        if reservation.status == MeetingReservation.Status.CANCELLED.value:
            raise errors.ConflictError(message=_('会议预定已取消'))

        now_ts = int(lib_time.time())
        if reservation.start_time <= now_ts:
            raise errors.ConflictError(message=_('已过会议预定开始时间'))

        if reservation.email_notice_id:
            raise errors.ConflictError(message=_('会议会前提醒通知已发送'))

        reservation.advance_notice_minutes = advance_minutes
        reservation.save(update_fields=['advance_notice_seconds', 'need_notice_time', 'update_time'])
        return reservation

    @staticmethod
    def add_operate_log(content: str, reservation_id: str, operator: str):
        try:
            MeetingReservationLog.add_log(
                log_type=MeetingReservationLog.LogType.OPERATE.value,
                operate_status=MeetingReservationLog.OperateStatus.OK.value,
                content=content, reservation_id=reservation_id, operator=operator
            )
        except Exception as e:
            pass

    @staticmethod
    def add_room_reserve_log(operate_status: str, content: str, reservation_id: str, operator: str):
        try:
            MeetingReservationLog.add_log(
                log_type=MeetingReservationLog.LogType.ROOM.value, operate_status=operate_status,
                content=content, reservation_id=reservation_id, operator=operator
            )
        except Exception as e:
            pass
